{
 "metadata": {
  "name": ""
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "First Steps with numba"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import numba\n",
      "print(numba.__version__)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "0.11.1-262-g7bf9498\n"
       ]
      }
     ],
     "prompt_number": 1
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Introduction to numba"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Numba allows the compilation of selected portions of Python code to native code, using llvm as its backend. This allows the selected functions to execute at a speed competitive with code generated by C compilers.\n",
      "\n",
      "It works at the function level. We can take a function, generate native code for that function as well as the wrapper code needed to call it directly from Python. This compilation is done on-the-fly and in-memory.\n",
      "\n",
      "In this notebook I will illustrate some very simple usage of numba."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "A simple example"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Let's start with a simple, yet time consuming function: a Python implementation of bubblesort. This bubblesort implementation works on a NumPy array.\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def bubblesort(X):\n",
      "    N = len(X)\n",
      "    for end in range(N, 1, -1):\n",
      "        for i in range(end - 1):\n",
      "            cur = X[i]\n",
      "            if cur > X[i + 1]:\n",
      "                tmp = X[i]\n",
      "                X[i] = X[i + 1]\n",
      "                X[i + 1] = tmp"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now, let's try the function, this way we check that it works. First we'll create an array of sorted values and randomly shuffle them:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import numpy as np\n",
      "\n",
      "original = np.arange(0.0, 10.0, 0.01, dtype='f4')\n",
      "shuffled = original.copy()\n",
      "np.random.shuffle(shuffled)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 3
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now we'll create a copy and do our bubble sort on the copy:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [
      "sorted = shuffled.copy()\n",
      "bubblesort(sorted)\n",
      "print(np.array_equal(sorted, original))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "True\n"
       ]
      }
     ],
     "prompt_number": 4
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Let's see how it behaves in execution time:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "sorted[:] = shuffled[:]\n",
      "%timeit sorted[:] = shuffled[:]; bubblesort(sorted)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1 loops, best of 3: 366 ms per loop\n"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Note that as execution time may depend on its input and the function itself is destructive, I make sure to use the same input in all the timings, by copying the original shuffled array into the new one. %timeit makes several runs and takes the best result, if the copy wasn't done inside the timing code the vector would only be unsorted in the first iteration. As bubblesort works better on vectors that are already sorted, the next runs would be selected and we will get the time when running bubblesort in an already sorted array. In our case the copy time is minimal, though:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%timeit sorted[:] = shuffled[:]"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1000000 loops, best of 3: 1.47 \u00b5s per loop\n"
       ]
      }
     ],
     "prompt_number": 6
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Compiling a function with numba.jit using an explicit function signature"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Let's get a numba version of this code running. One way to compile a function is by using the *numba.jit* decorator with an explicit signature. Later, we will see that we can get by without providing such a *signature* by letting *numba* figure out the _signatures_ by itself. However, it is useful to know what the signature is, and what role it has in *numba*.\n",
      "\n",
      "First, let's start by peeking at the numba.jit string-doc:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "print(numba.jit.__doc__)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "jit([signature_or_function, [locals={}, [target='cpu',\n",
        "            [**targetoptions]]]])\n",
        "\n",
        "    The function can be used as the following versions:\n",
        "\n",
        "    1) jit(signature, [target='cpu', [**targetoptions]]) -> jit(function)\n",
        "\n",
        "        Equivalent to:\n",
        "\n",
        "            d = dispatcher(function, targetoptions)\n",
        "            d.compile(signature)\n",
        "\n",
        "        Create a dispatcher object for a python function and default\n",
        "        target-options.  Then, compile the funciton with the given signature.\n",
        "\n",
        "        Example:\n",
        "\n",
        "            @jit(\"void(int32, float32)\")\n",
        "            def foo(x, y):\n",
        "                return x + y\n",
        "\n",
        "    2) jit(function) -> dispatcher\n",
        "\n",
        "        Same as old autojit.  Create a dispatcher function object that\n",
        "        specialize at call site.\n",
        "\n",
        "        Example:\n",
        "\n",
        "            @jit\n",
        "            def foo(x, y):\n",
        "                return x + y\n",
        "\n",
        "    3) jit([target='cpu', [**targetoptions]]) -> configured_jit(function)\n",
        "\n",
        "        Same as old autojit and 2).  But configure with target and default\n",
        "        target-options.\n",
        "\n",
        "\n",
        "        Example:\n",
        "\n",
        "            @jit(target='cpu', nopython=True)\n",
        "            def foo(x, y):\n",
        "                return x + y\n",
        "\n",
        "    Target Options\n",
        "    ---------------\n",
        "    The CPU (default target) defines the following:\n",
        "\n",
        "        - nopython: [bool]\n",
        "\n",
        "            Set to True to disable the use of PyObjects and Python API\n",
        "            calls.  The default behavior is to allow the use of PyObjects and\n",
        "            Python API.  Default value is False.\n",
        "\n",
        "        - forceobj: [bool]\n",
        "\n",
        "            Set to True to force the use of PyObjects for every value.  Default\n",
        "            value is False.\n",
        "\n",
        "    \n"
       ]
      }
     ],
     "prompt_number": 7
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "So let's make a compiled version of our bubblesort:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "bubblesort_jit = numba.jit(\"void(f4[:])\")(bubblesort)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 8
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "At this point, **bubblesort_jit** contains the compiled function -wrapped so that is directly callable from Python- generated from the original bubblesort function. Note that there is a fancy parameter *\"void(f4[:])\"* that is passed. That parameter describes the *signature* of the function to generate (more on this later).\n",
      "\n",
      "Let's check that it works:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "sorted[:] = shuffled[:] # reset to shuffled before sorting\n",
      "bubblesort_jit(sorted)\n",
      "print(np.array_equal(sorted, original))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "True\n"
       ]
      }
     ],
     "prompt_number": 9
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Now let's compare the time it takes to execute the compiled function compared to the original"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%timeit sorted[:] = shuffled[:]; bubblesort_jit(sorted)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1000 loops, best of 3: 1.56 ms per loop\n"
       ]
      }
     ],
     "prompt_number": 10
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%timeit sorted[:] = shuffled[:]; bubblesort(sorted)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1 loops, best of 3: 375 ms per loop\n"
       ]
      }
     ],
     "prompt_number": 11
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Bear in mind that numba.jit is a decorator, although for practical reasons in this tutorial we will be calling it like a function to have access to both, the original function and the jitted one. In many practical uses, the decorator syntax may be more appropriate. With the decorator syntax our sample will look like this:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "@numba.jit(\"void(f4[:])\")\n",
      "def bubblesort_jit(X):\n",
      "    N = len(X)\n",
      "    for end in range(N, 1, -1):\n",
      "        for i in range(end - 1):\n",
      "            cur = X[i]\n",
      "            if cur > X[i + 1]:\n",
      "                tmp = X[i]\n",
      "                X[i] = X[i + 1]\n",
      "                X[i + 1] = tmp"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 12
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Signature"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "In order to generate fast code, the compiler needs type information for the code. This allows a direct mapping from the Python operations to the appropriate machine instruction without any type check/dispatch mechanism. In numba, in most cases it suffices to specify the types for the parameters. In many cases, numba can deduce types for intermediate values as well as the return value using *type inference*. For convenience, it is also possible to specify in the signature the type of the *return value*"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A *numba.jit* compiled function will only work when called with the right type of arguments (it may, however, perform some conversions on types that it considers equivalent)."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "A *signature* contains the return type as well as the argument types. One way to specify the signature is using a string, like in our example. The *signature* takes the form: `<return type> ( <arg1 type>, <arg2 type>, ... )`. The types may be scalars or arrays (NumPy arrays). In our example, `void(f4[:])`, it means a function with no return (return type is `void`) that takes as unique argument an one-dimensional array of 4 byte floats `f4[:]`. Starting with numba version 0.12 the result type is optional. In that case the signature will look like the following: `<arg1 type>, <arg2 type>, ...`. When the signature doesn't provide a type for the return value, the type is *inferred*."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "One way to specify the signature is by using such a string, the type for each argument being based on NumPy dtype strings for base types. Array types are also supported by using [:] type notation, where [:] is a one-dimensional strided array, [::1] is a one-dimensional contiguous array, [:,:] a bidimensional strided array, [:,:,:] a tridimiensional array, and so on. There are other ways to build the signature, you can find more details on signatures in its documentation page."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Some sample signatures follow:\n",
      "\n",
      "| signature | meaning |\n",
      "|-----------|---------|\n",
      "| `void(f4[:], u8)` | a function with no return value taking a one-dimensional array of single precision floats and a 64-bit unsigned integer. |\n",
      "| `i4(f8)` |\u00a0a function returning a 32-bit signed integer taking a double precision float as argument. |\n",
      "| `void(f4[:,:],f4[:,:])`| a function with no return value taking two 2-dimensional arrays as arguments. |\n",
      "\n",
      "For a more in-depth explanation on supported types you can take a look at the \"Numba types\" notebook tutorial."
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Compiling a function without providing a function signature (autojit functionality)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Starting with numba version 0.12, it is possible to use *numba.jit* without providing a type-signature for the function. This functionality was provided by *numba.autojit* in previous versions of *numba*. The old *numba.autojit* has been deprecated in favour of this signature-less version of *numba.jit*.\n",
      "\n",
      "When no *type-signature* is provided, the decorator returns wrapper code that will automatically create and run a *numba* compiled version when called. When called, resulting function will infer the types of the arguments being used. That information will be used to generate the *signature* to be used when compiling. The resulting compiled function will be called with the provided arguments.\n",
      "\n",
      "For performance reasons, functions are cached so that code is only compiled once for a given signature. It is possible to call the function with different signatures, in that case, different native code will be generated and the right version will be chosen based on the argument types."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "For most uses, using jit without a signature will be the simplest option."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "bubblesort_autojit = numba.jit(bubblesort)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 20
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%timeit sorted[:] = shuffled[:]; bubblesort_autojit(sorted)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1 loops, best of 3: 1.39 ms per loop\n"
       ]
      }
     ],
     "prompt_number": 21
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Some extra remarks"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "There is no magic, there are several details that is good to know about numba."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "First, compiling takes time. Luckily enough it will not be a lot of time, specially for small functions. But when compiling many functions with many specializations the time may add up. Numba tries to do its best by caching compilation as much as possible though, so no time is spent in spurious compilation. It does its best to be *lazy* regarding compilation, this allows not paying the compilation time for code that is not used."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Second, not all code is compiled equal. There will be code that *numba* compiles down to an efficient native function. Sometimes the code generated has to fallback to the Python object system and its dispatch semantics. Other code may not compile at all.\n",
      "\n",
      "When targeting the \"cpu\" target (the default), *numba* will either generate:\n",
      "\n",
      "+ Fast native code -also called 'nopython'-. The compiler was able to infer all the types in the function, so it can translate the code to a fast native routine without making use of the Python runtime.\n",
      "\n",
      "+ Native code with calls to the Python run-time -also called object mode-. The compiler was not able to infer all the types, so that at some point a value was typed as a generic 'object'. This means the full native version can't be used. Instead, numba generates code using the Python run-time that should be faster than actual interpretation but quite far from what you could expect from a full native function.\n",
      "\n",
      "By default, the 'cpu' target tries to compile the function in 'nopython' mode. If this fails, it tries again in object mode."
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "This example shows how falling back to Python objects may cause a slowdown in the generated code:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "@numba.jit(\"void(i1[:])\")\n",
      "def test(value):\n",
      "    for i in xrange(len(value)):\n",
      "        value[i] = i % 100\n",
      "\n",
      "from decimal import Decimal\n",
      "@numba.jit(\"void(i1[:])\")\n",
      "def test2(value):\n",
      "    for i in xrange(len(value)):\n",
      "        value[i] = i % Decimal(100)\n",
      "\n",
      "res = np.zeros((10000,), dtype=\"i1\")"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 15
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%timeit test(res)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "10000 loops, best of 3: 34.5 \u00b5s per loop\n"
       ]
      }
     ],
     "prompt_number": 16
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "%timeit test2(res)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1 loops, best of 3: 347 ms per loop\n"
       ]
      }
     ],
     "prompt_number": 17
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "It is possible to force a failure if the *nopython* code generation fails. This allows getting some feedback about  whether it is possible to generate code for a given function that doesn't rely on the Python run-time. This can help when trying to write fast code, as object mode can have a huge performance penalty."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "@numba.jit(\"void(i1[:])\", nopython=True)\n",
      "def test(value):\n",
      "    for i in xrange(len(value)):\n",
      "        value[i] = i % 100"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 18
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "On the other hand, *test2* fails if we pass the *nopython* keyword:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "@numba.jit(\"void(i1[:])\", nopython=True)\n",
      "def test2(value):\n",
      "    for i in xrange(len(value)):\n",
      "        value[i] = i % Decimal(100)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "TypingError",
       "evalue": "Untyped global name 'Decimal'\nFile \"<ipython-input-19-6038b783c49c>\", line 4",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypingError\u001b[0m                               Traceback (most recent call last)",
        "\u001b[0;32m<ipython-input-19-6038b783c49c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m@\u001b[0m\u001b[0mnumba\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"void(i1[:])\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnopython\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mtest2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mxrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m         \u001b[0mvalue\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0mDecimal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m100\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/decorators.pyc\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(func)\u001b[0m\n\u001b[1;32m    125\u001b[0m         disp = dispatcher(py_func=func,  locals=locals,\n\u001b[1;32m    126\u001b[0m                           targetoptions=targetoptions)\n\u001b[0;32m--> 127\u001b[0;31m         \u001b[0mdisp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcompile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msig\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    128\u001b[0m         \u001b[0mdisp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdisable_compile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    129\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mdisp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/dispatcher.pyc\u001b[0m in \u001b[0;36mcompile\u001b[0;34m(self, sig, locals, **targetoptions)\u001b[0m\n\u001b[1;32m    100\u001b[0m             cres = compiler.compile_extra(typingctx, targetctx, self.py_func,\n\u001b[1;32m    101\u001b[0m                                           \u001b[0margs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreturn_type\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mreturn_type\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 102\u001b[0;31m                                           flags=flags, locals=locs)\n\u001b[0m\u001b[1;32m    103\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    104\u001b[0m             \u001b[0;31m# Check typing error if object mode is used\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/compiler.pyc\u001b[0m in \u001b[0;36mcompile_extra\u001b[0;34m(typingctx, targetctx, func, args, return_type, flags, locals)\u001b[0m\n\u001b[1;32m     77\u001b[0m                                                                    \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     78\u001b[0m                                                                    \u001b[0mreturn_type\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 79\u001b[0;31m                                                                    locals)\n\u001b[0m\u001b[1;32m     80\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     81\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mflags\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0menable_pyobject\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/compiler.pyc\u001b[0m in \u001b[0;36mtype_inference_stage\u001b[0;34m(typingctx, interp, args, return_type, locals)\u001b[0m\n\u001b[1;32m    156\u001b[0m         \u001b[0minfer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mseed_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mk\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    157\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 158\u001b[0;31m     \u001b[0minfer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuild_constrain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    159\u001b[0m     \u001b[0minfer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpropagate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    160\u001b[0m     \u001b[0mtypemap\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrestype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcalltypes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minfer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0munify\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/typeinfer.pyc\u001b[0m in \u001b[0;36mbuild_constrain\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    271\u001b[0m         \u001b[0;32mfor\u001b[0m \u001b[0mblk\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mutils\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdict_itervalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mblocks\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    272\u001b[0m             \u001b[0;32mfor\u001b[0m \u001b[0minst\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mblk\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 273\u001b[0;31m                 \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconstrain_statement\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    274\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    275\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mpropagate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/typeinfer.pyc\u001b[0m in \u001b[0;36mconstrain_statement\u001b[0;34m(self, inst)\u001b[0m\n\u001b[1;32m    368\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mconstrain_statement\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minst\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    369\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mir\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mAssign\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 370\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtypeof_assign\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    371\u001b[0m         \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mir\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSetItem\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    372\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtypeof_setitem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/typeinfer.pyc\u001b[0m in \u001b[0;36mtypeof_assign\u001b[0;34m(self, inst)\u001b[0m\n\u001b[1;32m    390\u001b[0m                                              src=value.name, loc=inst.loc))\n\u001b[1;32m    391\u001b[0m         \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mir\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mGlobal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 392\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtypeof_global\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minst\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtarget\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    393\u001b[0m         \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mir\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mExpr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    394\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtypeof_expr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minst\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtarget\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;32m/Users/ovillellas/anaconda/envs/numba-test/lib/python2.7/site-packages/numba/typeinfer.pyc\u001b[0m in \u001b[0;36mtypeof_global\u001b[0;34m(self, inst, target, gvar)\u001b[0m\n\u001b[1;32m    470\u001b[0m             \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    471\u001b[0m                 raise TypingError(\"Untyped global name '%s'\" % gvar.name,\n\u001b[0;32m--> 472\u001b[0;31m                                   loc=inst.loc)\n\u001b[0m\u001b[1;32m    473\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0massumed_immutables\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minst\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    474\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtypevars\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mtarget\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlock\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgvty\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
        "\u001b[0;31mTypingError\u001b[0m: Untyped global name 'Decimal'\nFile \"<ipython-input-19-6038b783c49c>\", line 4"
       ]
      }
     ],
     "prompt_number": 19
    }
   ],
   "metadata": {}
  }
 ]
}
